home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 52811 / 52811.xpi / chrome / content / AES / armour.js < prev    next >
Encoding:
JavaScript  |  2009-07-14  |  10.1 KB  |  371 lines

  1.  
  2. //  Varieties of ASCII armour for binary data
  3.  
  4.     var maxLineLength = 64;             // Maximum line length for armoured text
  5.     
  6.     /*                        Hexadecimal Armour
  7.     
  8.         A message is encoded in Hexadecimal armour by expressing its
  9.     bytes as a hexadecimal string which is prefixed by a sentinel
  10.     of "?HX?" and suffixed by "?H", then broken into lines no
  11.     longer than maxLineLength.  Armoured messages use lower case
  12.     letters for digits with decimal values of 0 through 15, but
  13.     either upper or lower case letters are accepted when decoding
  14.     a message.  The hexadecimal to byte array interconversion
  15.     routines in aes.js do most of the heavy lifting here.  */
  16.     
  17.     var hexSentinel = "?HX?", hexEndSentinel = "?H";
  18.     
  19.     //    Encode byte array in hexadecimal armour
  20.     
  21.     function armour_hex(b) {
  22.         var h = hexSentinel + byteArrayToHex(b) + hexEndSentinel;
  23.     var t = "";
  24.     while (h.length > maxLineLength) {
  25. //dump("h.length", h.length);
  26.         t += h.substring(0, maxLineLength) + "\n";
  27.         h = h.substring(maxLineLength, h.length);
  28.     }
  29. //dump("h.final_length", h.length);
  30.     t += h + "\n";
  31.     return t;
  32.     }
  33.     
  34.     /*    Decode string in hexadecimal armour to byte array.  If the
  35.         string supplied contains a start and/or end sentinel,
  36.     only characters within the sentinels will be decoded.
  37.     Non-hexadecimal digits are silently ignored, which
  38.     automatically handles line breaks.  We might want to
  39.     diagnose invalid characters as opposed to ignoring them.  */
  40.     
  41.     function disarm_hex(s) {
  42.         var hexDigits = "0123456789abcdefABCDEF";
  43.     var hs = "", i;
  44.     
  45.     //  Extract hexadecimal data between sentinels, if present
  46.     
  47.     if ((i = s.indexOf(hexSentinel)) >= 0) {
  48.         s = s.substring(i + hexSentinel.length, s.length);
  49.     }
  50.     if ((i = s.indexOf(hexEndSentinel)) >= 0) {
  51.         s = s.substring(0, i);
  52.     }
  53.     
  54.     //  Assemble string of valid hexadecimal digits
  55.     
  56.     for (i = 0; i < s.length; i++) {
  57.         var c = s.charAt(i);
  58.         if (hexDigits.indexOf(c) >= 0) {
  59.             hs += c;
  60.         }
  61.     }
  62. //dump("hs", hs);
  63.     return hexToByteArray(hs);
  64.     }
  65.  
  66.     /*                        Codegroup Armour
  67.     
  68.         Codegroup armour encodes a byte string into a sequence of five
  69.     letter code groups like spies used in the good old days.  The
  70.     first group of a message is always "ZZZZZ" and the last "YYYYY";
  71.     the decoding process ignores any text outside these start and
  72.     end sentinels.  Bytes are encoded as two letters in the range
  73.     "A" to "X", each encoding four bits of the byte.  Encoding uses
  74.     a pseudorandomly generated base letter and wraps around modulo
  75.     24 to spread encoded letters evenly through the alphabet.  (This
  76.     refinement is purely aesthetic; the base letter sequence is
  77.     identical for all messages and adds no security.  If the message
  78.     does not fill an even number of five letter groups, the last
  79.     group is padded to five letters with "Z" characters, which are
  80.     ignored when decoding.  */
  81.     
  82.     var acgcl, acgt, acgg;
  83.     
  84.     //    Output next codegroup, flushing current line if it's full
  85.     
  86.     function armour_cg_outgroup() {
  87.         if (acgcl.length > maxLineLength) {
  88.         acgt += acgcl + "\n";
  89.         acgcl = "";
  90.         }
  91.     if (acgcl.length > 0) {
  92.         acgcl += " ";
  93.     }
  94.     acgcl += acgg;
  95.     acgg = "";
  96.     }
  97.     
  98.     /*    Add a letter to the current codegroup, emitting it when
  99.         it reaches five letters.  */
  100.     
  101.     function armour_cg_outletter(l) {
  102.         if (acgg.length >= 5) {
  103.         armour_cg_outgroup();
  104.     }
  105.     acgg += l;
  106.     }
  107.     
  108.     var codegroupSentinel = "ZZZZZ";
  109.     
  110.     function armour_codegroup(b) {
  111.         var charBase = ("A").charCodeAt(0);
  112.     
  113.     acgcl = codegroupSentinel;
  114.     acgt = "";
  115.     acgg = "";
  116.     
  117.     var cgrng = new LEcuyer(0xbadf00d);
  118.     for (i = 0; i < b.length; i++) {
  119.        var r = cgrng.nextInt(23);
  120.        armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] >> 4) & 0xF)) + r) % 24));
  121.        r = cgrng.nextInt(23);
  122.        armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] & 0xF)) + r) % 24)));
  123.     }
  124.     delete cgrng;
  125.     
  126.     //  Generate nulls to fill final codegroup if required
  127.     
  128.     while (acgg.length < 5) {
  129.         armour_cg_outletter("Z");
  130.     }
  131.     armour_cg_outgroup();
  132.     
  133.     //  Append terminator group
  134.     
  135.     acgg = "YYYYY";
  136.     armour_cg_outgroup();
  137.     
  138.     //  Flush last line
  139.     
  140.     acgt += acgcl + "\n";
  141.     
  142.     return acgt;
  143.     }
  144.     
  145.     var dcgs, dcgi;
  146.     
  147.     /*    Obtain next "significant" character from message.  Characters
  148.         other than letters are silently ignored; both lower and upper
  149.     case letters are accepted.  */
  150.     
  151.     function disarm_cg_insig() {
  152.         while (dcgi < dcgs.length) {
  153.         var c = dcgs.charAt(dcgi++).toUpperCase();
  154.         if ((c >= "A") && (c <= "Z")) {
  155. //dump("c", c);
  156.             return c;
  157.             }
  158.         }
  159.     return "";
  160.     }
  161.     
  162.     //    Decode a message in codegroup armour
  163.     
  164.     function disarm_codegroup(s) {
  165.         var b = new Array();
  166.     var nz = 0, ba, bal = 0, c;
  167.     
  168.         dcgs = s;
  169.     dcgi = 0;
  170.     
  171.     //  Search for initial group of "ZZZZZ"
  172.     
  173.     while (nz < 5) {
  174.         c = disarm_cg_insig();
  175.         
  176.         if (c == "Z") {
  177.             nz++;
  178.         } else if (c == "") {
  179.             nz = 0;
  180.             break;
  181.         } else {
  182.             nz = 0;
  183.         }
  184.         }
  185.     
  186.     if (nz == 0) {
  187.         alert(strBundle.getFormattedString("armourCodegroupErrMessage", [ "Codegroup" ]));
  188.         return "";
  189.     }
  190.     
  191.     /*  Decode letter pairs from successive groups
  192.         and assemble into bytes.  */
  193.     
  194.     var charBase = ("A").charCodeAt(0);    
  195.     var cgrng = new LEcuyer(0xbadf00d);
  196.     for (nz = 0; nz < 2; ) {
  197.         c = disarm_cg_insig();
  198. //dump("c", c);
  199.         
  200.         if ((c == "Y") || (c == "")) {
  201.             break;
  202.         } else if (c != "Z") {
  203.             var r = cgrng.nextInt(23);
  204.             var n = c.charCodeAt(0) - charBase;
  205.         n = (n + (24 - r)) % 24;
  206. //dump("n", n);
  207.         if (nz == 0) {
  208.             ba = (n << 4);
  209.             nz++;
  210.         } else {
  211.             ba |= n;
  212.             b[bal++] = ba;
  213.             nz = 0;
  214.         }
  215.         }
  216.     }
  217.     delete cgrng;
  218.     
  219.     /*  Ponder how we escaped from the decoder loop and
  220.         issue any requisite warnings.  */
  221.     
  222.     var kbo = "  " + strBundle.getString('armourCodegroupMessage');
  223.     if (nz != 0) {
  224.         alert(strBundle.getFormattedString("armourCodegroupErrMessage2", [ "Codegroup:" ]) + kbo);
  225.     } else {
  226.         if (c == "Y") {
  227.         nz = 1;
  228.         while (nz < 5) {
  229.             c = disarm_cg_insig();
  230.                 if (c != "Y") {
  231.             break;
  232.             }
  233.             nz++;
  234.         }
  235.         if (nz != 5) {
  236.             alert(strBundle.getFormattedString("armourCodegroupErrMessage3", [ "Codegroup:" ]) + kbo);
  237.         }
  238.         } else {
  239.         alert(strBundle.getFormattedString("armourCodegroupErrMessage4", [ "Codegroup:" ]) + kbo);
  240.         }
  241.     }
  242.     
  243.     return b;
  244.     }
  245.     
  246.     /*                        Base64 Armour
  247.     
  248.         Base64 armour encodes a byte array as described in RFC 1341.  Sequences
  249.     of three bytes are encoded into groups of four characters from a set
  250.     of 64 consisting of the upper and lower case letters, decimal digits,
  251.     and the special characters "+" and "/".  If the input is not a multiple
  252.     of three characters, the end of the message is padded with one or two
  253.     "=" characters to indicate its actual length.  We prefix the armoured
  254.     message with "?b64" and append "?64b" to the end; if one or both
  255.     of these sentinels are present, text outside them is ignored.  You can
  256.     suppress the generation of sentinels in armour by setting base64addsent
  257.     false before calling armour_base64.  */
  258.     
  259.     
  260.     var base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
  261.         base64sent = "?b64", base64esent = "?64b", base64addsent = true;
  262.     
  263.     function armour_base64(b) {
  264.         var b64t = "";
  265.     var b64l = base64addsent ? base64sent : "";
  266.     
  267.     var i;
  268.     for (i = 0; i <= b.length - 3; i += 3) {
  269.         if ((b64l.length + 4) > maxLineLength) {
  270.             b64t += b64l + "\n";
  271.             b64l = "";
  272.             }
  273.         b64l += base64code.charAt(b[i] >> 2);
  274.         b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4));
  275.         b64l += base64code.charAt(((b[i + 1] & 0xF) << 2) | (b[i + 2] >> 6));
  276.         b64l += base64code.charAt(b[i + 2] & 0x3F);
  277.     }
  278.     
  279. //dump("b.length", b.length);  dump("i", i); dump("(b.length - i)", (b.length - i));
  280.     if ((b.length - i) == 1) {
  281.         b64l += base64code.charAt(b[i] >> 2);
  282.         b64l += base64code.charAt(((b[i] & 3) << 4));
  283.         b64l += "==";
  284.     } else if ((b.length - i) == 2) {
  285.         b64l += base64code.charAt(b[i] >> 2);
  286.         b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4));
  287.         b64l += base64code.charAt(((b[i + 1] & 0xF) << 2));
  288.         b64l += "=";
  289.     }
  290.  
  291.     if ((b64l.length + 4) > maxLineLength) {
  292.         b64t += b64l + "\n";
  293.         b64l = "";
  294.         }
  295.     if (base64addsent) {
  296.         b64l += base64esent;
  297.     }
  298.     b64t += b64l + "\n";
  299.     return b64t;
  300.     }
  301.     
  302.     function disarm_base64(s) {
  303.         var b = new Array();
  304.     var i = 0, j, c, shortgroup = 0, n = 0;
  305.     var d = new Array();
  306.     
  307.     if ((j = s.indexOf(base64sent)) >= 0) {
  308.         s = s.substring(j + base64sent.length, s.length);
  309.     }
  310.     if ((j = s.indexOf(base64esent)) >= 0) {
  311.         s = s.substring(0, j);
  312.     }
  313.     
  314.     /*  Ignore any non-base64 characters before the encoded
  315.         data stream and skip the type sentinel if present.  */
  316.     
  317.     while (i < s.length) {
  318.         if (base64code.indexOf(s.charAt(i)) != -1) {
  319.             break;
  320.         }
  321.         i++;
  322.     }
  323.     
  324.     /*  Decode the base64 data stream.  The decoder is
  325.         terminated by the end of the input string or
  326.         the occurrence of the explicit end sentinel.  */
  327.     
  328.     while (i < s.length) {
  329.         for (j = 0; j < 4; ) {
  330.             if (i >= s.length) {
  331.             if (j > 0) {
  332.                 alert(strBundle.getFormattedString("armourBase64ErrMessage", [ "Base64:" ]));
  333.                 return b;
  334.             }
  335.             break;
  336.         }
  337.         c = base64code.indexOf(s.charAt(i));
  338.         if (c >= 0) {
  339.             d[j++] = c;
  340.         } else if (s.charAt(i) == "=") {
  341.             d[j++] = 0;
  342.             shortgroup++;
  343.         } else if (s.substring(i, i + base64esent.length) == base64esent) {
  344. //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length));
  345. //dump("esent", i);
  346.             i = s.length;
  347.             continue;
  348.         } else {
  349. //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length));
  350. //dump("usent", i);
  351.                // Might improve diagnosis of improper character in else clause here
  352.         }
  353.         i++;
  354.         }
  355. //dump("d0", d[0]); dump("d1", d[1]); dump("d2", d[2]); dump("d3", d[3]); 
  356. //dump("shortgroup", shortgroup);
  357. //dump("n", n);
  358.         if (j == 4) {
  359.             b[n++] = ((d[0] << 2) | (d[1] >> 4)) & 0xFF;
  360.         if (shortgroup < 2) {
  361.             b[n++] = ((d[1] << 4) | (d[2] >> 2)) & 0xFF;
  362. //dump("(d[1] << 4) | (d[2] >> 2)", (d[1] << 4) | (d[2] >> 2));
  363.             if (shortgroup < 1) {
  364.                 b[n++] = ((d[2] << 6) | d[3]) & 0xFF;
  365.             }
  366.         }
  367.         }
  368.         }
  369.     return b;
  370.     }
  371.